// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CAEXObjectMetaInformationExtension.cs">
//   J. Prinz
// </copyright>
// <summary>
//   Extension class to handle MetaData with CAEXObjects
//   <para> author: J. Prinz </para>
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace AutomationMLMapper.AutomationML.Extensions
{
    using System.Collections.Generic;
    using System.Xml;

    using AMLEngineExtensions;

    using CAEX_ClassModel;

    /// <summary>
    ///   Extension class to handle MetaData with CAEXObjects
    ///   <para> author: J. Prinz </para>
    /// </summary>
    public static class CAEXObjectMetaInformationExtension
    {
        #region Public Methods and Operators

        /// <summary>
        /// this methods returns the meta information out of an existing AutomationML file for an AutomationML Object
        ///   <para>
        /// author: J. Prinz 
        /// </para>
        /// </summary>
        /// <param name="caexObject">
        /// the CAEX file 
        /// </param>
        /// <returns>
        /// a class containing all meta information, or null if no meta information is existing 
        /// </returns>
        public static IEnumerable<MetaObjectInformation> GetMetaInformationFromAutomationMLObject(
            this CAEXObject caexObject)
        {
            var addInfo = caexObject.AdditionalInformation;

            for (var i = 0; i < addInfo.Count; i++)
            {
                var x1 = addInfo[i];
                var writerHeaderNode = x1.Node.FirstChild;

                if (writerHeaderNode != null && writerHeaderNode.Name == "WriterHeader")
                {
                    var m = new MetaObjectInformation();

                    foreach (XmlElement childElement in writerHeaderNode)
                    {
                        switch (childElement.Name)
                        {
                            case "WriterObjectID":
                                m.WriterObjectID = childElement.InnerText;
                                break;
                            case "WriterID":
                                m.WriterID = childElement.InnerText;
                                break;
                        }
                    }

                    yield return m;
                }
            }
        }

        /// <summary>
        /// this methods returns the meta information out of an existing AutomationML file for an AutomationML Object
        ///   <para>
        /// author: J. Prinz 
        /// </para>
        /// </summary>
        /// <param name="caexObject">
        /// the CAEX file 
        /// </param>
        /// <param name="writerID">
        /// the Writer ID to look for
        /// </param>
        /// <returns>
        /// an enumerable MetaObjectInformation containing all meta information, or null if no meta information is existing 
        /// </returns>
        public static IEnumerable<MetaObjectInformation> GetMetaObjectInformation(
            this CAEXObject caexObject, string writerID)
        {
            var addInfo = caexObject.AdditionalInformation;

            for (var i = 0; i < addInfo.Count; i++)
            {
                var x1 = addInfo[i];
                var writerHeaderNode = x1.Node.FirstChild;

                if (writerHeaderNode != null && writerHeaderNode.Name == "WriterHeader")
                {
                    var found = false;

                    for (var j = 0; j < writerHeaderNode.ChildNodes.Count && !found; j++)
                    {
                        found = writerHeaderNode.ChildNodes[j].Name == "WriterID"
                                && writerHeaderNode.ChildNodes[j].InnerText == writerID;
                    }

                    if (found)
                    {
                        var m = new MetaObjectInformation();

                        foreach (XmlElement childElement in writerHeaderNode)
                        {
                            if (childElement.Name == "WriterObjectID")
                            {
                                m.WriterObjectID = childElement.InnerText;
                            }
                            else if (childElement.Name == "WriterID")
                            {
                                m.WriterID = childElement.InnerText;
                            }
                        }

                        yield return m;
                    }
                }
            }
        }

        /// <summary>
        /// this method is a short version of the setMetaInformation
        ///   <para>
        /// author: J. Prinz 
        /// </para>
        /// </summary>
        /// <param name="myCAEXObject">
        /// the CAEXObject 
        /// </param>
        /// <param name="m">
        /// the struct MetaInformation 
        /// </param>
        public static void SetMetaInformation(this CAEXObject myCAEXObject, MetaObjectInformation m)
        {
            if (m != null)
            {
                SetMetaObjectInformationForAutomationMLObject(myCAEXObject, m.WriterID, m.WriterObjectID);
            }
        }

        /// <summary>
        /// this function sets the meta information suggested to store tool specific object-IDs
        ///   <para>
        /// author: J. Prinz 
        /// </para>
        /// </summary>
        /// <param name="caexObject">
        /// the CAEXObject 
        /// </param>
        /// <param name="writerID">
        /// an ID of the writing tool 
        /// </param>
        /// <param name="writerObjectID">
        /// an ID of object of the writing tool 
        /// </param>
        public static void SetMetaObjectInformationForAutomationMLObject(
            this CAEXObject caexObject, string writerID, string writerObjectID)
        {
            var addInfo = caexObject.AdditionalInformation;

            // first find if there is an existing writer information corresponding to the current one
            for (var i = 0; i < addInfo.Count; i++)
            {
                var x1 = addInfo[i];
                var writerHeaderNode = x1.Node.FirstChild;

                if (writerHeaderNode != null)
                {
                    if (writerHeaderNode.Name == "WriterHeader")
                    {
                        var found = false;

                        for (var j = 0; j < writerHeaderNode.ChildNodes.Count && !found; j++)
                        {
                            found = writerHeaderNode.ChildNodes[j].Name == "WriterID"
                                    && writerHeaderNode.ChildNodes[j].InnerText == writerID;
                        }

                        if (found)
                        {
                            x1.Remove(); // x1.Node.RemoveChild(writerHeaderNode);
                        }
                    }
                }
            }

            var x2 = caexObject.New_AdditionalInformation();
            var additionalNode = x2.Node;
            var xdoc = caexObject.Node.OwnerDocument;

            // create writerHeader
            if (xdoc != null)
            {
                var writerHeader = xdoc.CreateElement("WriterHeader");
                additionalNode.AppendChild(writerHeader);

                // create writerID
                var elem = xdoc.CreateElement("WriterID");
                elem.InnerText = writerID;
                writerHeader.AppendChild(elem);

                // create writerVendor
                elem = xdoc.CreateElement("WriterObjectID");
                elem.InnerText = writerObjectID;
                writerHeader.AppendChild(elem);
            }
        }

        #endregion
    }
}